package com.mi.minal.module.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.mi.minal.common.util.JwtKit;
import com.mi.minal.module.system.service.DictService;
import com.mi.minal.module.system.service.SystemService;
import com.mi.minal.mybatis.entity.*;
import com.mi.rule.cache.CacheKit;
import com.mi.rule.db.core.MiPage;
import com.mi.rule.db.core.MiWrapper;
import com.mi.rule.db.dao.MiDao;
import com.mi.rule.resource.ResEntity;
import com.mi.rule.resource.ResourceHandler;
import com.mi.rule.util.MathKit;
import com.mi.rule.util.RequestKit;
import com.mi.rule.util.TreeKit;
import com.mi.rule.util.project.MiException;
import com.mi.rule.util.project.SRS;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 资源表 服务实现类
 * </p>
 *
 * @author 王永吉
 */
@Slf4j
@Service
public class SystemServiceImpl implements SystemService {

    //    @Transactional
    @Override
    public SRS test0() {
//        //一主多从
//        SysDict sysDict = new SysDict();
//        sysDict.setId("200");
//        sysDict.setCode("标记" + biaoji);
//        sysDict.setValue("主库");
//        long deleteById1 = miDao.deleteById(SysDict.class, 200);
//        long insert1 = miDao.insert(sysDict);
//        String master = miDao.selectById(SysDict.class, 200).getValue();
//
//        SysDict sysDict1 = new SysDict();
//        sysDict1.setId("200");
//        sysDict1.setCode("标记" + biaoji);
//        sysDict1.setValue("从库1");
//        long deleteById2 = miDao.deleteById(SysDict.class, 200, "slave_1");
//        long insert2 = miDao.insert(sysDict1, "slave_1");
//        String slave1 = miDao.selectById(SysDict.class, 200, "slave_1").getValue();
//
//
//        SysDict sysDict2 = new SysDict();
//        sysDict2.setId("200");
//        sysDict2.setCode("标记" + biaoji);
//        sysDict2.setValue("从库2");
//        long deleteById3 = miDao.deleteById(SysDict.class, 200, "slave_2");
//        long insert3 = miDao.insert(sysDict2, "slave_2");
//        String slave2 = miDao.selectById(SysDict.class, 200, "slave_2").getValue();

//        if (1 == 1)throw new MiException("故意报错");
//
//        SRS srs = test1();
//        SRS srs1 = test2();
//        SRS srs2 = test3();
//        System.out.println(srs.toString());
//        System.out.println(srs1.toString());
//        System.out.println(srs2.toString());
        return SRS.bySuccess();
    }

    @DS("master")
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public SRS test1(String biaoji) {
        SysDict sysDict = new SysDict();
        sysDict.setId("200");
        sysDict.setCode("00000" + biaoji);
        sysDict.setValue("主库" + biaoji);
        long deleteById1 = dao.deleteById(SysDict.class, 200);
        long insert1 = dao.insert(sysDict);
        String master = dao.selectById(SysDict.class, 200).getValue();
//        return SRS.bySuccess();
        if (1 == 1) throw new MiException("故意报错");
        return SRS.bySuccess(master);
    }

    @DS("slave_1")
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public SRS test2(String biaoji) { //一主多从
        SysDict sysDict1 = new SysDict();
        sysDict1.setId("200");
        sysDict1.setCode("00000" + biaoji);
        sysDict1.setValue("从库1" + biaoji);
        long deleteById2 = dao.deleteById(SysDict.class, 200);
        long insert2 = dao.insert(sysDict1);
        String slave1 = dao.selectById(SysDict.class, 200).getValue();
        return SRS.bySuccess(slave1);
//        return SRS.bySuccess();
    }

    @Override
    @DS("slave_2")
    @Transactional(rollbackFor = Throwable.class)
    public SRS test3(String biaoji) { //一主多从
        SysDict sysDict2 = new SysDict();
        sysDict2.setId("200");
        sysDict2.setCode("00000" + biaoji);
        sysDict2.setValue("从库2" + biaoji);
        long deleteById3 = dao.deleteById(SysDict.class, 200);
        long insert3 = dao.insert(sysDict2);
        String slave2 = dao.selectById(SysDict.class, 200).getValue();
//        return SRS.bySuccess();
        return SRS.bySuccess(slave2);
    }


    @Autowired
    private MiDao dao;
    @Autowired
    private DictService dictService;

    //资源列表
    @Override
    public List<SysResource> resources() {
        Object o = CacheKit.get(key_resource_list);
        if (o == null) {
            List<SysResource> list = dao.list(SysResource.class);
            CacheKit.set(key_resource_list, list);
            return list;
        }
        return (List<SysResource>) o;
    }

    //角色列表
    @Override
    public List<SysRole> roles() {
        Object o = CacheKit.get(key_role_list);
        if (o == null) {
            List<SysRole> list = dao.list(SysRole.class);
            CacheKit.set(key_role_list, list);
            return list;
        }
        return (List<SysRole>) o;
    }

    //菜单列表
    @Override
    public List<SysMenu> menus() {
        Object o = CacheKit.get(key_menu_list);
        if (o == null) {
            List<SysMenu> list = dao.list(SysMenu.class);
            CacheKit.set(key_menu_list, list);
            return dao.list(SysMenu.class);
        }
        return (List<SysMenu>) o;
    }

    //角色菜单Urls
    @Override
    public List<String> roleMenuUrls(Object roleId) {
        Object o = CacheKit.get(key_role_menu_url + roleId);
        if (o == null) {
            List<String> menuIds = dao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select(SysLinkRoleMenu.MENU_ID).eq(SysLinkRoleMenu.ROLE_ID, roleId), String.class);
            List<SysMenu> sysMenus = dao.listByIds(SysMenu.class, menuIds);
            List<String> urls = sysMenus.stream().map(SysMenu::getPath).collect(Collectors.toList());
            CacheKit.set(key_role_menu_url + roleId, urls);
            return urls;
        }
        return (List<String>) o;
    }

    //角色菜单Ids
    @Override
    public List<String> roleMenuIds(String roleId) {
        Object o = CacheKit.get(key_role_menu_id + roleId);
        if (o == null) {
            List<String> menuIds = dao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select(SysLinkRoleMenu.MENU_ID).eq(SysLinkRoleMenu.ROLE_ID, roleId), String.class);
            List<SysMenu> sysMenus = dao.listByIds(SysMenu.class, menuIds);
            List<String> ids = sysMenus.stream().map(SysMenu::getId).collect(Collectors.toList());
            CacheKit.set(key_role_menu_id + roleId, ids);
            return ids;
        }
        return (List<String>) o;
    }

    //角色菜单Ids
    @Override
    public List<String> roleMenuIds(List roleIds) {
        HashSet<String> hashSet = new HashSet<>();
        for (Object roleId : roleIds) {
            hashSet.addAll(roleMenuIds(roleId + ""));
        }
        return new ArrayList<>(hashSet);
    }

    //角色菜单List
    @Override
    public List<SysMenu> roleMenuList(String roleId) {
        Object o = CacheKit.get(key_role_menu_list + roleId);
        if (o == null) {
            List<String> menuIds = dao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select(SysLinkRoleMenu.MENU_ID).eq(SysLinkRoleMenu.ROLE_ID, roleId), String.class);
            List<SysMenu> sysMenus = dao.listByIds(SysMenu.class, menuIds);
            CacheKit.set(key_role_menu_list + roleId, sysMenus);
            return sysMenus;
        }
        return (List<SysMenu>) o;
    }

    //角色菜单List(不包含PID=0)
    @Override
    public List<SysMenu> roleMenuList(List roleIds) {
        HashSet<SysMenu> hashSet = new HashSet<>();
        for (Object roleId : roleIds) {
            List<SysMenu> menuList = roleMenuList(roleId + "");
            hashSet.addAll(menuList);
        }
        return new ArrayList<>(hashSet);
    }

    //角色资源Urls
    @Override
    public List<String> roleResourceUrls(Object roleId) {
        Object o = CacheKit.get(key_role_resource_url + roleId);
        if (o == null) {
            List<String> resourceIds = dao.listObjs(new MiWrapper<>(SysLinkRoleResource.class).select(SysLinkRoleResource.RESOURCE_ID).eq(SysLinkRoleResource.ROLE_ID, roleId), String.class);
            List<SysResource> sysMenus = dao.listByIds(SysResource.class, resourceIds);
            List<String> urls = sysMenus.stream().map(SysResource::getUrl).collect(Collectors.toList());
            CacheKit.set(key_role_resource_url + roleId, urls);
            return urls;
        }
        return (List<String>) o;
    }

    //角色资源Ids
    @Override
    public List<String> roleResourceIds(String roleId) {
        Object o = CacheKit.get(key_role_resource_id + roleId);
        if (o == null) {
            List<String> resourceIds = dao.listObjs(new MiWrapper<>(SysLinkRoleResource.class).select(SysLinkRoleResource.RESOURCE_ID).eq(SysLinkRoleResource.ROLE_ID, roleId), String.class);
            List<SysResource> sysMenus = dao.listByIds(SysResource.class, resourceIds);
            List<String> ids = sysMenus.stream().map(SysResource::getId).collect(Collectors.toList());
            CacheKit.set(key_role_resource_id + roleId, ids);
            return ids;
        }
        return (List<String>) o;
    }

    //角色资源Ids
    @Override
    public List<String> roleResourceIds(List roleIds) {
        HashSet<String> hashSet = new HashSet<>();
        for (Object roleId : roleIds) {
            hashSet.addAll(roleResourceIds(roleId + ""));
        }
        return new ArrayList<>(hashSet);
    }

    //角色资源Urls
    @Override
    public List<String> roleResourceUrls2(List<?> roleIds) {
        HashSet<String> hashSet = new HashSet<>();
        for (Object roleId : roleIds) {
            List<String> strings = roleResourceUrls(roleId);
            hashSet.addAll(strings);
        }
        return new ArrayList<>(hashSet);
    }

    //角色资源List
    @Override
    public List<SysResource> roleResourceList(String roleId) {
        Object o = CacheKit.get(key_role_resource_list + roleId);
        if (o == null) {
            List<String> resourceIds = dao.listObjs(new MiWrapper<>(SysLinkRoleResource.class).select(SysLinkRoleResource.RESOURCE_ID).eq(SysLinkRoleResource.ROLE_ID, roleId), String.class);
            List<SysResource> sysMenus = dao.listByIds(SysResource.class, resourceIds);
            CacheKit.set(key_role_resource_list + roleId, sysMenus);
            return sysMenus;
        }
        return (List<SysResource>) o;
    }

    //角色资源Ids
    @Override
    public List<SysResource> roleResourceList(List roleIds) {
        HashSet<SysResource> hashSet = new HashSet<>();
        for (Object roleId : roleIds) {
            hashSet.addAll(roleResourceList(roleId + ""));
        }
        return new ArrayList<>(hashSet);
    }

    //1.清除已失效资源
    //2.添加新资源
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SRS systemResourceCleanAdd(SRS param) {
        //项目中的全部资源
        ArrayList<ResEntity> resMList = ResourceHandler.getResMList();
        ArrayList<ResEntity> resCList = ResourceHandler.getResCList();
        ArrayList<ResEntity> resList = new ArrayList<>();
        resList.addAll(resCList);
        resList.addAll(resMList);
        List<String> resUrlList = resList.stream().map(ResEntity::getUrl).collect(Collectors.toList());

        //数据库中的全部资源
        List<SysResource> dbResList = dao.list(SysResource.class);
        List<String> dbUrlList = dbResList.stream().map(SysResource::getUrl).collect(Collectors.toList());

        //筛选Method
        //待删除模块 -- deleteResCIds
        //新增模块   -- insertResC
        //可更新模块 -- updateResC
        ArrayList<SysResource> insertResCList = new ArrayList<>();
        ArrayList<String> deleteResCIds = new ArrayList<>();
        ArrayList<SysResource> updateResCList = new ArrayList<>();

        //筛选controller
        for (ResEntity resEntity : resList) {
            String resUrl = resEntity.getUrl();
            //待新增  -- 项目中存在，数据库中不存在
            if (!dbUrlList.contains(resUrl)) {
                SysResource sysResource = new SysResource();
                sysResource.setName(resEntity.getName());
                sysResource.setParentName(resEntity.getParentName());
                sysResource.setUrl(resEntity.getUrl());
                sysResource.setPid("0");//初始为0后面会做修改
                insertResCList.add(sysResource);
            }
        }
        for (SysResource sysResource : dbResList) {
            String dbUrl = sysResource.getUrl();
            //待更新 -- 数据库中存在，项目中存在
            if (resUrlList.contains(dbUrl)) {
                List<ResEntity> collect = resList.stream().filter(it -> it.getUrl().equals(dbUrl)).collect(Collectors.toList());
                ResEntity resEntity = collect.get(0);
                sysResource.setName(resEntity.getName());
                sysResource.setParentName(resEntity.getParentName());
                updateResCList.add(sysResource);
            }

            //待删除 -- 数据库中存在，项目中不存在
            if (!resUrlList.contains(dbUrl)) {
                deleteResCIds.add(sysResource.getId());
            }
        }

        //删除失效资源
        if (deleteResCIds.size() > 0) {
            //删除资源表
            long l = dao.deleteByIds(SysResource.class, deleteResCIds);
            //删除角色资源关联表
            MiWrapper<SysLinkRoleResource> wrapper = new MiWrapper<>(SysLinkRoleResource.class);
            wrapper.in(SysLinkRoleResource.ROLE_ID, deleteResCIds);
            long delete = dao.delete(wrapper);
            log.info("失效资源ids:{}", deleteResCIds);
            log.info("删除失效资源      共{}条", l);
            log.info("删除角色资源关联表 共{}条", delete);
        }

        //更新资源
        if (updateResCList.size() > 0) {
            //更新资源
            long l = dao.updateBatchById(updateResCList);
            log.info("更新资源      共{}条", l);
        }

        //添加新资源
        //
        //批量插入资源
        long l = dao.insertBatch(insertResCList);
        log.info("批量插入资源     共{}条", l);
        log.info("批量插入资源      {}", JSON.toJSONString(insertResCList));

        //把新增 和 修改的资源 合并
        ArrayList<SysResource> allResC = new ArrayList<>();
        allResC.addAll(insertResCList);
        allResC.addAll(updateResCList);

        //遍历 新增模块
        for (SysResource insertRes : insertResCList) {
            //处理非根节点
            if (!insertRes.getName().equals(insertRes.getParentName())) {
                String parentName = insertRes.getParentName();
                //从合并的模块集合内
                for (SysResource sysResource : allResC) {
                    //找到自己的pid
                    if (sysResource.getName().equals(parentName)) {
                        insertRes.setPid(sysResource.getId());
                        break;
                    }
                }
            }
        }

        //更新这个集合，模块新增完成
        long l1 = dao.updateBatchById(insertResCList);
        log.info("全部资源新增完成      共{}条", l1);
        log.info("全部资源新增完成      {}", JSON.toJSONString(insertResCList));
        //TODO 这里注释
        List<SysResource> list = dao.list(SysResource.class);
        List<SysResource> gen = list.stream().filter(it -> it.getPid().equals("0")).collect(Collectors.toList());
        List<SysResource> notGen = list.stream().filter(it -> !it.getPid().equals("0")).collect(Collectors.toList());
        log.info("list     {}", JSON.toJSONString(list));
        log.info("gen     {}", JSON.toJSONString(gen));
        log.info("notGen  {}", JSON.toJSONString(notGen));

        ArrayList<JSONObject> arrayList = TreeKit.listToTree(gen, notGen);
        log.info("全部资源树化结果      {}", JSON.toJSONString(arrayList));
        resources();
        return SRS.bySuccess(CacheKit.get("all_resource_list"));
    }

    @Override
    public SRS refreshRoleMenuAndResource(SRS param) {
        //缓存全部角色
        List<SysRole> sysRoles = roles();
        //查询角色菜单关联表
        List<String> roleIds = sysRoles.stream().map(SysRole::getId).collect(Collectors.toList());

        //缓存角色资源，角色菜单
        for (String roleId : roleIds) {
            //当前角色的全部资源
            List<String> roleResourceIds = dao.listObjs(new MiWrapper<>(SysLinkRoleResource.class).select("resource_id").eq("role_id", roleId), String.class);
            //当前角色的全部菜单
            List<String> roleMenuIds = dao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select("menu_id").eq("role_id", roleId), String.class);

            updateRoleResource(SRS.create().set("roleId", roleId).set("resourceIds", roleResourceIds));
            updateRoleMenu(SRS.create().set("roleId", roleId).set("menuIds", roleMenuIds));
        }
        return SRS.bySuccess();
    }

    //修改角色资源
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SRS updateRoleResource(SRS param) {
        String roleId = param.getString("roleId");
        JSONArray resourceIds = param.getJSONArray("resourceIds");

        //修改角色资源关联表
        //删除
        dao.delete(new MiWrapper<>(SysLinkRoleResource.class).eq(SysLinkRoleResource.ROLE_ID, roleId));

        //重新插入
        ArrayList<SysLinkRoleResource> objects = new ArrayList<>();
        for (Object resourceId : resourceIds) {
            SysLinkRoleResource sysLinkRoleResource = new SysLinkRoleResource();
            sysLinkRoleResource.setRoleId(roleId);
            sysLinkRoleResource.setResourceId(resourceId.toString());
            objects.add(sysLinkRoleResource);
        }
        dao.insertBatch(objects);

        //刷新缓存
        CacheKit.delete(key_role_resource_url + roleId);
        CacheKit.delete(key_role_resource_list + roleId);

        return SRS.bySuccess();
    }

    //修改角色菜单
    @Override
    public SRS updateRoleMenu(SRS param) {
        String roleId = param.getString("roleId");
        JSONArray menuIds = param.getJSONArray("menuIds");

        //修改角色菜单关联表
        //删除
        dao.delete(new MiWrapper<>(SysLinkRoleMenu.class).eq(SysLinkRoleMenu.ROLE_ID, roleId));
        //重新插入
        ArrayList<SysLinkRoleMenu> objects = new ArrayList<>();
        for (Object menuId : menuIds) {
            SysLinkRoleMenu linkRoleMenu = new SysLinkRoleMenu();
            linkRoleMenu.setRoleId(roleId);
            linkRoleMenu.setMenuId(menuId.toString());
            objects.add(linkRoleMenu);
        }
        dao.insertBatch(objects);

        //删除缓存
        deleteRoleMenuCache(roleId);
        return SRS.bySuccess();
    }

    //更新已存在资源的功能和名称
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SRS resourceRefreshAll(SRS param) {
        //更新已存在资源的功能和名称

        //项目中存在的资源
        ArrayList<ResEntity> listRes = ResourceHandler.getResMList();
        //数据库中的全部资源
        List<SysResource> listDbRes = dao.list(SysResource.class);
        for (SysResource sysResource : listDbRes) {
            for (ResEntity resEntity : listRes) {
                if (sysResource.getUrl().equals(resEntity.getUrl())) {
                    sysResource.setName(resEntity.getName());
                    //sysResource.setAbility(resEntity.getAbility());
                }
            }
        }
        long l = dao.updateBatchById(listDbRes);
        log.info("已刷新资源 共{}条", l);
        return SRS.bySuccess();
    }

    //刷新某个用户的角色
    @Override
    public SRS refreshUserRole(String userId) {
        return SRS.bySuccess();
    }

    //获取角色资源
    @Override
    public List<SysLinkRoleResource> getRoleResource(String roleId) {
        return (List<SysLinkRoleResource>) CacheKit.get("RoleResource-" + roleId);
    }

    //获取角色菜单
    @Override
    public List<SysLinkRoleMenu> getRoleMenu(String roleId) {
        return (List<SysLinkRoleMenu>) CacheKit.get("RoleMenu-" + roleId);
    }

    @Override
    public SRS insertDict(SysDict dict) {
        dao.insert(dict);
        CacheKit.delete(key_dict_list);
        return SRS.bySuccess();
    }

    @Override
    public SRS deleteDict(Object[] ids) {
        dao.deleteByIds(SysDict.class, Arrays.asList(ids));
        CacheKit.delete(key_dict_list);
        return SRS.bySuccess();
    }

    @Override
    public SRS updateDict(SysDict dict) {
        dao.update(dict);
        CacheKit.delete(key_dict_list);
        return SRS.bySuccess();
    }

    @Override
    public SRS pageDict(SRS param) {
        MiWrapper<SysDict> wrapper = new MiWrapper<>(SysDict.class);
        wrapper.eq("1", 1);

        wrapper.like(notBlank(param.get("id")), SysDict.ID, param.get("id"));
        wrapper.like(notBlank(param.get("code")), SysDict.CODE, param.get("code"));
        wrapper.like(notBlank(param.get("value")), SysDict.VALUE, param.get("value"));
        wrapper.like(notBlank(param.get("name")), SysDict.NAME, param.get("name"));
        MiPage<SysDict> page = dao.page(new MiPage<>(param), wrapper);
        return SRS.bySuccess(page);
    }

    @Override
    public SRS listDict(SRS param) {
        MiWrapper<SysDict> wrapper = new MiWrapper<>(SysDict.class);
        wrapper.eq("1", 1);
        wrapper.like(notBlank(param.get("id")), SysDict.ID, param.get("id"));
        List<SysDict> list = dao.list(wrapper);
        return SRS.bySuccess(list);
    }

    @Override
    public SRS infoDict(SRS param) {
        SysDict dict = dao.selectById(SysDict.class, param.getString("id"));
        return SRS.bySuccess(dict);
    }

    @Override
    public SRS insertMenu(SysMenu menu) {
        dao.insert(menu);
        //删除菜单缓存
        CacheKit.delete(key_menu_list);
        return SRS.bySuccess();
    }

    @Override
    public SRS deleteMenu(Object[] ids) {
        dao.deleteByIds(SysMenu.class, Arrays.asList(ids));

        //删除菜单缓存
        CacheKit.delete(key_menu_list);
        //删除角色菜单缓存
        List<String> roleIds = dao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select(SysLinkRoleMenu.ROLE_ID).in(SysLinkRoleMenu.MENU_ID, Arrays.asList(ids)), String.class);
        for (String roleId : roleIds) {
            CacheKit.delete(key_role_menu_list + roleId);
        }
        return SRS.bySuccess();
    }

    @Override
    public SRS updateMenu(SysMenu menu) {
        dao.update(menu);
        //删除菜单缓存
        CacheKit.delete(key_menu_list);
        //删除角色菜单缓存
        String menuId = menu.getId();
        List<String> roleIds = dao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select(SysLinkRoleMenu.ROLE_ID).eq(SysLinkRoleMenu.MENU_ID, menuId), String.class);
        for (String roleId : roleIds) {
            deleteRoleMenuCache(roleId);
        }
        return SRS.bySuccess();
    }

    @Override
    public SRS pageMenu(SRS param) {
        MiWrapper<SysMenu> wrapper = new MiWrapper<>(SysMenu.class);
        wrapper.eq("1", 1);
        wrapper.like(notBlank(param.get("id")), SysMenu.ID, param.get("id"));
        wrapper.like(notBlank(param.get("title")), SysMenu.TITLE, param.get("title"));
        wrapper.like(notBlank(param.get("path")), SysMenu.PATH, param.get("path"));
        MiPage<SysMenu> page = dao.page(new MiPage<>(param), wrapper);
        return SRS.bySuccess(page);
    }

    @Override
    public SRS listMenu(SRS param) {
        MiWrapper<SysMenu> wrapper = new MiWrapper<>(SysMenu.class);
        wrapper.eq("1", 1);

        wrapper.like(notBlank(param.get("id")), SysMenu.ID, param.get("id"));
        List<SysMenu> list = dao.list(wrapper);
        return SRS.bySuccess(list);
    }

    @Override
    public SRS infoMenu(SRS param) {
        SysMenu dict = dao.selectById(SysMenu.class, param.getString("id"));
        return SRS.bySuccess(dict);
    }

    @Override
    public SRS updateResource(SysResource resource) {
        dao.update(resource);
        // 删除资源缓存
        CacheKit.delete(key_resource_list);
        // 删除角色资源缓存
        String resourceId = resource.getId();
        List<String> roleIds = dao.listObjs(new MiWrapper<>(SysLinkRoleResource.class).select(SysLinkRoleResource.ROLE_ID).eq(SysLinkRoleResource.RESOURCE_ID, resourceId), String.class);
        for (String roleId : roleIds) {
            CacheKit.delete(key_role_resource_url + roleId);
            CacheKit.delete(key_role_resource_list + roleId);
        }
        return SRS.bySuccess();
    }

    @Override
    public SRS pageResource(SRS param) {
        MiWrapper<SysResource> wrapper = new MiWrapper<>(SysResource.class);
        wrapper.eq("1", 1);

        wrapper.like(notBlank(param.get("id")), SysResource.ID, param.get("id"));
        wrapper.like(notBlank(param.get("name")), SysResource.NAME, param.get("name"));
        wrapper.like(notBlank(param.get("url")), SysResource.URL, param.get("url"));
        MiPage<SysResource> page = dao.page(new MiPage<>(param), wrapper);
        return SRS.bySuccess(page);
    }

    @Override
    public SRS listResource(SRS param) {
        MiWrapper<SysResource> wrapper = new MiWrapper<>(SysResource.class);
        wrapper.eq("1", 1);

        wrapper.like(notBlank(param.get("id")), SysResource.ID, param.get("id"));
        List<SysResource> list = dao.list(wrapper);
        return SRS.bySuccess(list);
    }

    @Override
    public SRS infoResource(SRS param) {
        SysResource dict = dao.selectById(SysResource.class, param.getString("id"));
        return SRS.bySuccess(dict);
    }

    @Override
    public SRS insertSysRole(SysRole role) {
        dao.insert(role);
        //删除角色缓存
        CacheKit.delete(key_role_list);
        return SRS.bySuccess();

    }

    @Override
    public SRS deleteSysRole(Object[] ids) {
        dao.deleteByIds(SysRole.class, Arrays.asList(ids));
        //删除角色相关缓存
        CacheKit.delete(key_role_list);
        for (Object roleId : ids) {
            deleteRoleMenuCache(roleId);
            deleteRoleResourceCache(roleId);
        }
        return SRS.bySuccess();

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SRS updateSysRole(SRS param) {
        //修改角色信息
        SysRole sysRole = new SysRole();
        sysRole.setId(param.getString("id"));
        sysRole.setCode(param.getString("code"));
        sysRole.setName(param.getString("name"));
        dao.update(sysRole);

        //修改角色菜单
        MiWrapper<SysLinkRoleMenu> wrapper1 = new MiWrapper<>(SysLinkRoleMenu.class);
        wrapper1.eq(SysLinkRoleMenu.ROLE_ID, sysRole.getId());
        dao.delete(wrapper1);
        ArrayList<SysLinkRoleMenu> linkRoleMenus = new ArrayList<>();
        for (Object menuId : param.getJSONArray("menuCheckIds")) {
            SysLinkRoleMenu linkRoleMenu = new SysLinkRoleMenu();
            linkRoleMenu.setRoleId(sysRole.getId());
            linkRoleMenu.setMenuId(menuId + "");
            linkRoleMenus.add(linkRoleMenu);
        }
        dao.insertBatch(linkRoleMenus);

        //修改角色资源
        MiWrapper<SysLinkRoleResource> wrapper2 = new MiWrapper<>(SysLinkRoleResource.class);
        wrapper2.eq(SysLinkRoleResource.ROLE_ID, sysRole.getId());
        dao.delete(wrapper2);
        ArrayList<SysLinkRoleResource> linkRoleResources = new ArrayList<>();
        for (Object resourceId : param.getJSONArray("resourceCheckIds")) {
            SysLinkRoleResource linkRoleResource = new SysLinkRoleResource();
            linkRoleResource.setRoleId(sysRole.getId());
            linkRoleResource.setResourceId(resourceId + "");
            linkRoleResources.add(linkRoleResource);
        }
        dao.insertBatch(linkRoleResources);
        //删除缓存
        CacheKit.delete(key_role_list);
        deleteRoleMenuCache(sysRole.getId());
        deleteRoleResourceCache(sysRole.getId());
        return SRS.bySuccess();
    }

    @Override
    public SRS pageSysRole(SRS param) {
        MiWrapper<SysRole> wrapper = new MiWrapper<>(SysRole.class);
        wrapper.eq("1", 1);
        wrapper.like(notBlank(param.get("id")), SysRole.ID, param.get("id"));
        wrapper.like(notBlank(param.get("name")), SysRole.NAME, param.get("name"));
        wrapper.like(notBlank(param.get("code")), SysRole.CODE, param.get("code"));
        MiPage<SysRole> page = dao.page(new MiPage<>(param), wrapper);
        return SRS.bySuccess(page);
    }

    @Override
    public SRS listSysRole(SRS param) {
        MiWrapper<SysRole> wrapper = new MiWrapper<>(SysRole.class);
        wrapper.eq("1", 1);

        wrapper.like(notBlank(param.get("id")), SysRole.ID, param.get("id"));
        List<SysRole> list = dao.list(wrapper);
        return SRS.bySuccess(list);
    }

    @Override
    public SRS infoSysRole(SRS param) {
        SysRole dict = dao.selectById(SysRole.class, param.getString("id"));
        return SRS.bySuccess(dict);
    }

    @Override
    public SRS login(SRS param) {
        String passwordParam = param.getString("password");
        String account = param.get("account") + "";
        String password = addSalt(passwordParam);

        //用户信息
        MiWrapper<SysUser> wrapper = new MiWrapper<>(SysUser.class);
        SysUser userInfo = dao.selectOne(
                wrapper.eq(SysUser.ACCOUNT, account)
                        .eq(SysUser.PASSWORD, password)
                        .eq(SysUser.IS_USE, 1)
                        .eq(SysUser.IS_DELETE, 2));
        if (userInfo == null) {
            return SRS.byError("账号或密码错误！");
        }

        //角色信息
        List<String> roleIds = dao.listObjs(
                new MiWrapper<>(SysLinkRoleUser.class)
                        .select(SysLinkRoleUser.ROLE_ID)
                        .eq(SysLinkRoleUser.USER_ID, userInfo.getId()),
                String.class
        );

        //TODO 检验是否可登录
        //        if (!roleIds.contains("1")) {
        //            return SRS.byError("登录权限不足");
        //        }

        //生成Token
        String loginIp = RequestKit.getIpAddr();
        SRS tokenParam = SRS.create()
                .set("userId", userInfo.getId())
                .set("roleIds", roleIds)
                .set("ip", loginIp);
        String token = JwtKit.createToken(tokenParam, dictService.getValue("system_jwt_token_time_out", (2 * 60 * 1000) + ""));
        String refreshToken = MathKit.getMD5(UUID.randomUUID().toString());

        //更新用户信息
        userInfo.setPassword(null);
        userInfo.setLoginIp(loginIp);
        userInfo.setLoginTime(LocalDateTime.now());
        userInfo.setRefreshToken(refreshToken);
        dao.update(userInfo);

        //角色
        List<SysRole> roles = roles().stream().filter(it -> roleIds.contains(it.getId())).collect(Collectors.toList());

        //菜单
        ArrayList<SysMenu> sysMenus = getSysMenus(roleIds);
        sysMenus.sort(Comparator.comparing(SysMenu::getSort));

        return SRS.bySuccess(
                SRS.create()
                        .set("userInfo", userInfo)
                        .set("roles", roles)
                        .set("menus", sysMenus)
                        .set("token", token)
                        .set("refreshToken", refreshToken)
        );
    }


    @Override
    public SRS updatePassword(SRS param) {
        SysUser userInfo = dao.selectById(SysUser.class, userId());
        String oldPassword = addSalt(param.getString("oldPassword"));
        String newPassword = addSalt(param.getString("newPassword"));

        if (!oldPassword.equals(userInfo.getPassword())) {
            return SRS.byError("原密码输入错误");
        }

        userInfo.setPassword(newPassword);
        dao.update(userInfo);
        return SRS.bySuccess();
    }

    @Override
    public SRS insertSysUser(SysUser param) {
        String password = addSalt(param.getPassword());
        param.setPassword(password);
        dao.insert(param);
        return SRS.bySuccess();
    }

    @Override
    public SRS deleteSysUser(Object[] ids) {
        dao.deleteByIds(SysMenu.class, Arrays.asList(ids));
        return SRS.bySuccess();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SRS updateSysUser(SysUser param) {
        //修改角色资源
        List roleIds = param.getParamRoleIds();
        if (roleIds != null && roleIds.size() > 0) {
            MiWrapper<SysLinkRoleUser> wrapper = new MiWrapper<>(SysLinkRoleUser.class);
            wrapper.in(SysLinkRoleUser.USER_ID, roleIds);
            dao.delete(wrapper);
            ArrayList<SysLinkRoleUser> linkRoleUsers = new ArrayList<>();
            for (Object roleId : roleIds) {
                SysLinkRoleUser linkRoleUser = new SysLinkRoleUser();
                linkRoleUser.setRoleId(roleId + "");
                linkRoleUser.setUserId(param.getId());
                linkRoleUsers.add(linkRoleUser);
            }
            dao.insertBatch(linkRoleUsers);
        }


        //修改用户信息
        dao.update(param);

        return SRS.bySuccess();
    }

    @Override
    public SRS listSysUser(SysUser param) {
        return SRS.bySuccess(dao.list(SysUser.class));
    }

    @Override
    public SRS pageSysUser(SRS param) {
        MiWrapper<SysUser> wrapper = new MiWrapper<>(SysUser.class);

        wrapper.select("sys_user.*", "group_concat( lu.role_id ) AS roleIds", "group_concat( sr.name ) AS roleNames");
        wrapper.leftJoin("sys_link_role_user lu", "lu.user_id = sys_user.id");
        wrapper.leftJoin("sys_role sr", "sr.id = lu.role_id");

        wrapper.eq("1", 1);
        wrapper.like(notBlank(param.get("name")), SysUser.NAME, param.get("name"));
        wrapper.like(notBlank(param.get("account")), SysUser.ACCOUNT, param.get("account"));
        wrapper.groupBy("sys_user.id ");

        MiPage<SysUser> page = dao.page(new MiPage<>(param), wrapper);
        return SRS.bySuccess(page);
    }

    @Override
    public SRS infoSysUser(SRS param) {
        return SRS.bySuccess(dao.selectById(SysUser.class, param.getString("id")));
    }

    @Override
    public SRS refreshToken(SRS param) {
        return null;
    }

    @Override
    public SRS resetPassword(SRS param) {
        String password = addSalt(param.getString("password"));
        SysUser sysUser = new SysUser();
        sysUser.setId(userId());
        sysUser.setPassword(password);

        dao.update(sysUser);
        return SRS.bySuccess();
    }

    @Override
    public void updateVersion(Object o) {
        String front_admin_version = dictService.getValue("front_admin_version");
        String system_server_api_version = dictService.getValue("system_server_api_version");

        int html_version = Integer.parseInt(front_admin_version) + 1;
        int api_version = Integer.parseInt(system_server_api_version) + 1;
        dictService.setValue("front_admin_version", html_version + "");
        dictService.setValue("system_server_api_version", api_version + "");

        log.info("更新版本号 front_admin_version  {}===>{} ", front_admin_version, html_version);
        log.info("更新版本号 system_server_api_version   {}===>{} ", system_server_api_version, api_version);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SRS refreshMenu(SysMenu[] menus) {
        //前台当前全部路由
        List<SysMenu> frontMenus = Arrays.asList(menus);
        List<String> frontMenuPath = frontMenus.stream().map(SysMenu::getPath).collect(Collectors.toList());
        //数据库中的全部路由
        List<SysMenu> dbMenus = dao.list(SysMenu.class);
        List<String> dbMenuPath = dbMenus.stream().map(SysMenu::getPath).collect(Collectors.toList());

        //筛选处理结果
        List<SysMenu> insertMenus = new ArrayList<>();
        List<SysMenu> updateMenus = new ArrayList<>();
        List<String> deleteMenuIds = new ArrayList<>();
        for (SysMenu frontMenu : frontMenus) {
            String path = frontMenu.getPath();
            //数据库中不存在-添加
            if (!dbMenuPath.contains(path)) {
                insertMenus.add(frontMenu);
            }
            //数据库中存在-更新
            if (dbMenuPath.contains(path)) {
                List<SysMenu> dbList = dbMenus.stream().filter(it -> it.getPath().equals(path)).collect(Collectors.toList());
                List<SysMenu> frontList = frontMenus.stream().filter(it -> it.getPath().equals(path)).collect(Collectors.toList());
                frontList.get(0).setId(dbList.get(0).getId());
                updateMenus.add(frontList.get(0));
            }
        }
        for (SysMenu dbMenu : dbMenus) {
            //前端不存在-删除
            if (!frontMenuPath.contains(dbMenu.getPath())) {
                deleteMenuIds.add(dbMenu.getId());
            }
        }

        //删除不存在的菜单
        if (deleteMenuIds.size() > 0) {
            //删除菜单
            dao.deleteByIds(SysMenu.class, deleteMenuIds);
            //删除关联
            dao.delete(new MiWrapper<>(SysLinkRoleMenu.class).in(SysLinkRoleMenu.MENU_ID, deleteMenuIds));
        }

        //更新存在的
        dao.updateBatchById(updateMenus);

        //添加新增的
        //批量插入
        dao.insertBatch(insertMenus);
        //修改自己的父ID
        ArrayList<SysMenu> allMenus = new ArrayList<>();
        allMenus.addAll(insertMenus);
        allMenus.addAll(updateMenus);
        for (SysMenu insertMenu : insertMenus) {
            String path = insertMenu.getPath();
            String parentPath = insertMenu.getParentPath();
            if (path.equals(parentPath) || parentPath == null) {
                insertMenu.setPid("0");
                insertMenu.setParentPath(parentPath);
                continue;
            }

            for (SysMenu menu : allMenus) {
                if (menu.getPath().equals(parentPath)) {
                    insertMenu.setPid(menu.getId());
                    insertMenu.setParentPath(menu.getPath());

                }
            }

        }

        //批量修改
        dao.updateBatchById(insertMenus);

        //删除缓存
        CacheKit.delete(key_menu_list);
        //角色菜单
        if (deleteMenuIds.size() > 0) {
            List<String> roleIds = dao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).in(SysLinkRoleMenu.MENU_ID, deleteMenuIds), String.class);
            for (String roleId : roleIds) {
                deleteRoleMenuCache(roleId);
            }
        }

        return SRS.bySuccess();
    }

    //     * 获取用户的全部菜单
    private ArrayList<SysMenu> getSysMenus(List<String> roleIds) {
        HashSet<SysMenu> hashSetMenus = new HashSet<>();
        List<SysMenu> menus = roleMenuList(roleIds);
        List<SysMenu> menus1 = menus();
        for (SysMenu menu : menus) {
            String pid = menu.getPid();
            List<SysMenu> collect = menus1.stream().filter(it -> it.getId().equals(pid)).collect(Collectors.toList());
            hashSetMenus.addAll(collect);
        }
        hashSetMenus.addAll(menus);
        return new ArrayList<>(hashSetMenus);
    }


    //清除角色菜单缓存
    private void deleteRoleMenuCache(Object roleId) {
        CacheKit.delete(key_role_menu_url + roleId);
        CacheKit.delete(key_role_menu_id + roleId);
        CacheKit.delete(key_role_menu_list + roleId);
    }

    //删除角色资源缓存
    private void deleteRoleResourceCache(Object roleId) {
        CacheKit.delete(key_role_resource_url + roleId);
        CacheKit.delete(key_role_resource_id + roleId);
        CacheKit.delete(key_role_resource_list + roleId);
    }

    /**
     * 一堆缓存Key，放到哪里比较好呢？？？
     */
    //字典
    private final static String key_dict_list = "cache-system-dict-list";
    //菜单
    private final static String key_menu_list = "cache-system-menu-list";
    //角色
    private final static String key_role_list = "cache-system-role-list";
    //资源
    private final static String key_resource_list = "cache-system-resource-list";
    //角色资源
    private final static String key_role_resource_url = "cache-system-role-resource-url-";
    //角色资源
    private final static String key_role_resource_id = "cache-system-role-resource-id-";
    //角色资源
    private final static String key_role_resource_list = "cache-system-role-resource-list-";
    //角色菜单
    private final static String key_role_menu_url = "cache-system-role-menu-url-";
    //角色菜单
    private final static String key_role_menu_id = "cache-system-role-menu-id-";
    //角色菜单
    private final static String key_role_menu_list = "cache-system-role-menu-list-";
}